package encryption

import (
	"bufio"
	"bytes"
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/des"
	"crypto/hmac"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"fmt"
	"hash"
	"io"
	"os"
	"product/common/toolbox"
	"strings"
)

// Md5 Encrypt
// 参数：字符串
// 返回值：字符串
func Md5(str string) string {
	m := md5.New()
	m.Write([]byte(str))
	tmpArr := m.Sum(nil)
	return hex.EncodeToString(tmpArr)
}

// Md5ByBytes Md5 Bytes加密
// 参数：字节数组
// 返回值：字符串
func Md5ByBytes(b []byte) string {
	m := md5.New()
	m.Write(b)
	return hex.EncodeToString(m.Sum(nil))
}

// Md5WithSalt Md5 加盐加密
// 参数：字符串，盐值
// 返回值：字符串
func Md5WithSalt(val string, salt string) string {
	tmpStr := fmt.Sprintf("%s%s", val, salt)
	return Md5(tmpStr)
}

// GenerateSalt 生成盐值
// 返回值：字符串
func GenerateSalt() string {
	return toolbox.RandomStringToUpper(8,
		toolbox.LettersAndNumbers,
		true)
}

// Md5File 文件md5加密
// 参数：文件路径
// 返回值：字符串，错误
func Md5File(filename string) (string, error) {
	fileInfo, err := os.Stat(filename)
	if err != nil {
		return "", err
	}
	if fileInfo.IsDir() {
		return "", err
	}
	file, openErr := os.Open(filename)
	if openErr != nil {
		return "", openErr
	}
	defer func(file *os.File) {
		err = file.Close()
		if err != nil {

		}
	}(file)

	h := md5.New()
	chunkSize := 65536
	for buff, reader := make([]byte, chunkSize), bufio.NewReader(file); ; {
		n, readErr := reader.Read(buff)
		if readErr == nil {
			h.Write(buff[:n])
			continue
		}
		if readErr == io.EOF {
			break
		}
		return "", readErr
	}

	checkSum := fmt.Sprintf("%x", h.Sum(nil))
	return checkSum, nil

}

// Base64Encode Base64加密
// 参数：字符串，是否大写
// 返回值：字符串
func Base64Encode(val string) string {
	return base64.
		StdEncoding.
		EncodeToString([]byte(val))
}

// Base64Decode Base64解密
// 参数：字符串
// 返回值：字符串，错误
func Base64Decode(val string) (string, error) {
	data, err := base64.StdEncoding.DecodeString(val)
	return string(data), err
}

// GenerateKey 随机生成key 32位
func GenerateKey() []byte {
	key := sha256.Sum256([]byte(toolbox.RandomStrings(32, toolbox.LettersAndNumbers)))
	return key[:]
}

// HmacMd5 Hmac加密
// 参数：字符串，密钥
// 返回值：字符串
func HmacMd5(str, key string) string {
	h := hmac.New(md5.New, []byte(key))
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum([]byte("")))
}

// HmacSha1 Hmac加密
// 参数：字符串，密钥
// 返回值：字符串
func HmacSha1(str, key string) string {
	h := hmac.New(sha1.New, []byte(key))
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum([]byte("")))
}

// HmacSha256 Hmac加密
// 参数：字符串，密钥
// 返回值：字符串
func HmacSha256(str, key string) string {
	h := hmac.New(sha256.New, []byte(key))
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum([]byte("")))
}

// HmacSha512 Hmac加密
// 参数：字符串，密钥
// 返回值：字符串
func HmacSha512(str, key string) string {
	h := hmac.New(sha512.New, []byte(key))
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum([]byte("")))
}

// Sha512 Sha512加密
// 参数：字符串
// 返回值：字符串
func Sha512(str string) string {
	s := sha512.New()
	s.Write([]byte(str))
	return hex.EncodeToString(s.Sum([]byte("")))
}

// Sha256 Sha256加密
// 参数：字符串
// 返回值：字符串
func Sha256(str string) string {
	s := sha256.New()
	s.Write([]byte(str))
	return hex.EncodeToString(s.Sum([]byte("")))
}

// ###################### 加密数据 ######################

// AesEcbEncrypt AES加密
// 参数：明文，密钥
// 返回值：密文
func AesEcbEncrypt(data, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	length := (len(data) + aes.BlockSize) / aes.BlockSize
	plain := make([]byte, length*aes.BlockSize)

	copy(plain, data)

	pad := byte(len(plain) - len(data))
	for i := len(data); i < len(plain); i++ {
		plain[i] = pad
	}

	encrypted := make([]byte, len(plain))
	newCipher, _ := aes.NewCipher(generateAesKey(key, size))

	for bs, be := 0, newCipher.BlockSize(); bs <= len(data); bs, be = bs+newCipher.BlockSize(), be+newCipher.BlockSize() {
		newCipher.Encrypt(encrypted[bs:be], plain[bs:be])
	}
	return encrypted
}

// AesEcbDecrypt AES解密
// 参数：密文，密钥
// 返回值：明文
func AesEcbDecrypt(encrypted, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}
	newCipher, _ := aes.NewCipher(generateAesKey(key, size))
	decrypted := make([]byte, len(encrypted))

	for bs, be := 0, newCipher.BlockSize(); bs < len(encrypted); bs, be = bs+newCipher.BlockSize(), be+newCipher.BlockSize() {
		newCipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
	}

	trim := 0
	if len(decrypted) > 0 {
		trim = len(decrypted) - int(decrypted[len(decrypted)-1])
	}

	return decrypted[:trim]
}

// AesCbcEncrypt AES加密 cbc模式
// 参数：明文，密钥
// 返回值：密文
func AesCbcEncrypt(data, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	block, _ := aes.NewCipher(key)
	data = pkcs7Padding(data, block.BlockSize())

	encrypted := make([]byte, aes.BlockSize+len(data))
	iv := encrypted[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(encrypted[aes.BlockSize:], data)

	return encrypted
}

// AesCbcDecrypt AES解密 cbc模式
// 参数：密文，密钥
// 返回值：明文
func AesCbcDecrypt(encrypted, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	block, _ := aes.NewCipher(key)

	iv := encrypted[:aes.BlockSize]
	encrypted = encrypted[aes.BlockSize:]

	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(encrypted, encrypted)

	decrypted := pkcs7UnPadding(encrypted)
	return decrypted
}

// AesCtrCrypt AES加密 ctr模式
// 参数：明文，密钥
// 返回值：密文
func AesCtrCrypt(data, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	block, _ := aes.NewCipher(key)

	iv := bytes.Repeat([]byte("1"), block.BlockSize())
	stream := cipher.NewCTR(block, iv)

	dst := make([]byte, len(data))
	stream.XORKeyStream(dst, data)

	return dst
}

// AesCfbEncrypt AES加密 cfb模式
// 参数：明文，密钥
// 返回值：密文
func AesCfbEncrypt(data, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	encrypted := make([]byte, aes.BlockSize+len(data))
	iv := encrypted[:aes.BlockSize]

	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(encrypted[aes.BlockSize:], data)

	return encrypted
}

// AesCfbDecrypt AES解密 cfb模式
// 参数：密文，密钥
// 返回值：明文
func AesCfbDecrypt(encrypted, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	if len(encrypted) < aes.BlockSize {
		panic("encrypted data is too short")
	}

	block, _ := aes.NewCipher(key)
	iv := encrypted[:aes.BlockSize]
	encrypted = encrypted[aes.BlockSize:]

	stream := cipher.NewCFBDecrypter(block, iv)

	stream.XORKeyStream(encrypted, encrypted)

	return encrypted
}

// AesOfbEncrypt AES加密 ofb模式
// 参数：明文，密钥
// 返回值：密文
func AesOfbEncrypt(data, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	data = pkcs7Padding(data, aes.BlockSize)
	encrypted := make([]byte, aes.BlockSize+len(data))
	iv := encrypted[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	stream := cipher.NewOFB(block, iv)
	stream.XORKeyStream(encrypted[aes.BlockSize:], data)

	return encrypted
}

// AesOfbDecrypt AES解密 ofb模式
// 参数：密文，密钥
// 返回值：明文
func AesOfbDecrypt(data, key []byte) []byte {
	size := len(key)
	if size != 16 && size != 24 && size != 32 {
		panic("key length must be 16 or 24 or 32")
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	iv := data[:aes.BlockSize]
	data = data[aes.BlockSize:]
	if len(data)%aes.BlockSize != 0 {
		return nil
	}

	decrypted := make([]byte, len(data))
	mode := cipher.NewOFB(block, iv)
	mode.XORKeyStream(decrypted, data)

	decrypted = pkcs7UnPadding(decrypted)

	return decrypted
}

// AesGcmEncrypt AES加密 gcm模式
// 参数：明文，密钥
// 返回值：密文
func AesGcmEncrypt(data, key []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		panic(err)
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		panic(err)
	}

	ciphertext := gcm.Seal(nonce, nonce, data, nil)

	return ciphertext
}

// AesGcmDecrypt AES解密 gcm模式
// 参数：密文，密钥
// 返回值：明文
func AesGcmDecrypt(data, key []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		panic(err)
	}

	nonceSize := gcm.NonceSize()
	if len(data) < nonceSize {
		panic("ciphertext too short")
	}

	nonce, ciphertext := data[:nonceSize], data[nonceSize:]
	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		panic(err)
	}

	return plaintext
}

// DesEcbEncrypt DES加密 ecb模式
// 参数：明文，密钥
// 返回值：密文
func DesEcbEncrypt(data, key []byte) []byte {
	length := (len(data) + des.BlockSize) / des.BlockSize
	plain := make([]byte, length*des.BlockSize)
	copy(plain, data)

	pad := byte(len(plain) - len(data))
	for i := len(data); i < len(plain); i++ {
		plain[i] = pad
	}

	encrypted := make([]byte, len(plain))
	newCipher, _ := des.NewCipher(generateDesKey(key))

	for bs, be := 0, newCipher.BlockSize(); bs <= len(data); bs, be = bs+newCipher.BlockSize(), be+newCipher.BlockSize() {
		newCipher.Encrypt(encrypted[bs:be], plain[bs:be])
	}

	return encrypted
}

// DesEcbDecrypt DES解密 ecb模式
// 参数：密文，密钥
// 返回值：明文
func DesEcbDecrypt(encrypted, key []byte) []byte {
	newCipher, _ := des.NewCipher(generateDesKey(key))
	decrypted := make([]byte, len(encrypted))

	for bs, be := 0, newCipher.BlockSize(); bs < len(encrypted); bs, be = bs+newCipher.BlockSize(), be+newCipher.BlockSize() {
		newCipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
	}

	trim := 0
	if len(decrypted) > 0 {
		trim = len(decrypted) - int(decrypted[len(decrypted)-1])
	}

	return decrypted[:trim]
}

// DesCbcEncrypt DES加密 cbc模式
// 参数：明文，密钥
// 返回值：密文
func DesCbcEncrypt(data, key []byte) []byte {
	size := len(key)
	if size != 8 {
		panic("key length must be 8")
	}

	block, _ := des.NewCipher(key)
	data = pkcs7Padding(data, block.BlockSize())

	encrypted := make([]byte, des.BlockSize+len(data))
	iv := encrypted[:des.BlockSize]

	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(encrypted[des.BlockSize:], data)

	return encrypted
}

// DesCbcDecrypt DES解密 cbc模式
// 参数：密文，密钥
// 返回值：明文
func DesCbcDecrypt(encrypted, key []byte) []byte {
	size := len(key)
	if size != 8 {
		panic("key length must be 8")
	}

	block, _ := des.NewCipher(key)

	iv := encrypted[:des.BlockSize]
	encrypted = encrypted[des.BlockSize:]

	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(encrypted, encrypted)

	decrypted := pkcs7UnPadding(encrypted)
	return decrypted
}

// DesCtrCrypt DES加密 ctr模式
// 参数：明文，密钥
// 返回值：密文
func DesCtrCrypt(data, key []byte) []byte {
	size := len(key)
	if size != 8 {
		panic("key length must be 8")
	}

	block, _ := des.NewCipher(key)

	iv := bytes.Repeat([]byte("1"), block.BlockSize())
	stream := cipher.NewCTR(block, iv)

	dst := make([]byte, len(data))
	stream.XORKeyStream(dst, data)

	return dst
}

// DesCfbEncrypt DES加密 cfb模式
// 参数：明文，密钥
// 返回值：密文
func DesCfbEncrypt(data, key []byte) []byte {
	size := len(key)
	if size != 8 {
		panic("key length must be 8")
	}

	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}

	encrypted := make([]byte, des.BlockSize+len(data))
	iv := encrypted[:des.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(encrypted[des.BlockSize:], data)

	return encrypted
}

// GenerateRsaKey 生成RSA密钥对
// 参数：密钥长度，私钥文件，公钥文件
// 返回值：错误信息
func GenerateRsaKey(keySize int, privateFile, publicFile string) error {
	// 生成私钥文件
	privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
	if err != nil {
		return errors.New("生成私钥出错")
	}
	derStream := x509.MarshalPKCS1PrivateKey(privateKey)
	block := pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: derStream,
	}
	file, createErr := os.Create(privateFile)
	if createErr != nil {
		panic(createErr)
	}
	err = pem.Encode(file, &block)
	if err != nil {
		return errors.New("私钥编码出错")
	}
	_ = file.Close()

	// 生成公钥文件
	publicKey := &privateKey.PublicKey
	derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		return errors.New("公钥编码出错")
	}
	block = pem.Block{
		Type:  "RSA PUBLIC KEY",
		Bytes: derPkix,
	}
	file, createErr = os.Create(publicFile)
	if createErr != nil {
		panic(createErr)
	}
	err = pem.Encode(file, &block)
	if err != nil {
		return errors.New("公钥编码出错")
	}
	_ = file.Close()
	return nil

}

// RsaEncrypt RSA加密
// 参数：明文，公钥文件
// 返回值：密文
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
	file, err := os.Open(pubKeyFileName)
	if err != nil {
		panic(err)
	}
	fileInfo, err := file.Stat()
	if err != nil {
		panic(err)
	}
	defer func(file *os.File) {
		err = file.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(file)
	buf := make([]byte, fileInfo.Size())

	_, err = file.Read(buf)
	if err != nil {
		panic(err)
	}

	block, _ := pem.Decode(buf)

	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	pubKey := pubInterface.(*rsa.PublicKey)

	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
	if err != nil {
		panic(err)
	}

	return cipherText
}

// RsaDecrypt RSA解密
// 参数：密文，私钥文件
// 返回值：明文
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
	file, err := os.Open(privateKeyFileName)
	if err != nil {
		panic(err)
	}
	fileInfo, err := file.Stat()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, fileInfo.Size())
	defer func(file *os.File) {
		err = file.Close()
		if err != nil {
			fmt.Println(err)
		}
	}(file)

	_, err = file.Read(buf)
	if err != nil {
		panic(err)
	}

	block, _ := pem.Decode(buf)

	priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		panic(err)
	}

	plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
	if err != nil {
		panic(err)
	}

	return plainText
}

// GenerateRsaKeyPair 生成RSA密钥对
// 参数：密钥长度
func GenerateRsaKeyPair(keySize int) (*rsa.PrivateKey, *rsa.PublicKey) {
	privateKey, _ := rsa.GenerateKey(rand.Reader, keySize)
	return privateKey, &privateKey.PublicKey
}

// RsaSign RSA签名
// 参数：签名哈希算法，明文，私钥文件
// 返回值：签名，错误信息
func RsaSign(hash crypto.Hash, data []byte, privateKeyFileName string) ([]byte, error) {
	privateKey, err := loadRasPrivateKey(privateKeyFileName)
	if err != nil {
		return nil, err
	}

	hashed, err := hashData(hash, data)
	if err != nil {
		return nil, err
	}

	return rsa.SignPKCS1v15(rand.Reader, privateKey, hash, hashed)
}

// RsaVerifySign 验证签名
// 参数：签名哈希算法，明文，签名，公钥文件
func RsaVerifySign(hash crypto.Hash, data, signature []byte, pubKeyFileName string) error {
	publicKey, err := loadRsaPublicKey(pubKeyFileName)
	if err != nil {
		return err
	}

	hashed, err := hashData(hash, data)
	if err != nil {
		return err
	}

	return rsa.VerifyPKCS1v15(publicKey, hash, hashed, signature)
}

func loadRsaPublicKey(filename string) (*rsa.PublicKey, error) {
	pubKeyData, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(pubKeyData)
	if block == nil {
		return nil, errors.New("failed to decode PEM block containing the public key")
	}

	var pubKey *rsa.PublicKey
	blockType := strings.ToUpper(block.Type)

	if blockType == "RSA PUBLIC KEY" {
		pubKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
		if err != nil {
			// todo: here should be a bug, should return nil, err
			key, err := x509.ParsePKIXPublicKey(block.Bytes)
			if err != nil {
				return nil, err
			}

			var ok bool
			pubKey, ok = key.(*rsa.PublicKey)
			if !ok {
				return nil, errors.New("failed to parse RSA private key")
			}
		}
	} else if blockType == "PUBLIC KEY" {
		key, err := x509.ParsePKIXPublicKey(block.Bytes)
		if err != nil {
			return nil, err
		}

		var ok bool
		pubKey, ok = key.(*rsa.PublicKey)
		if !ok {
			return nil, errors.New("failed to parse RSA private key")
		}

	} else {
		return nil, errors.New("unsupported key type")
	}

	return pubKey, nil
}

func loadRasPrivateKey(filename string) (*rsa.PrivateKey, error) {
	priKeyData, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(priKeyData)
	if block == nil {
		return nil, errors.New("failed to decode PEM block containing the private key")
	}

	var privateKey *rsa.PrivateKey
	blockType := strings.ToUpper(block.Type)

	// PKCS#1 format
	if blockType == "RSA PRIVATE KEY" {
		privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
		if err != nil {
			return nil, err
		}
	} else if blockType == "PRIVATE KEY" { // PKCS#8 format
		priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
		if err != nil {
			return nil, err
		}
		var ok bool
		privateKey, ok = priKey.(*rsa.PrivateKey)
		if !ok {
			return nil, errors.New("failed to parse RSA private key")
		}
	} else {
		return nil, errors.New("unsupported key type")
	}

	return privateKey, nil
}

func hashData(hash crypto.Hash, data []byte) ([]byte, error) {
	if !hash.Available() {
		return nil, errors.New("unsupported hash algorithm")
	}

	var hashed []byte

	switch hash {
	case crypto.SHA224:
		h := sha256.Sum224(data)
		hashed = h[:]
	case crypto.SHA256:
		h := sha256.Sum256(data)
		hashed = h[:]
	case crypto.SHA384:
		h := sha512.Sum384(data)
		hashed = h[:]
	case crypto.SHA512:
		h := sha512.Sum512(data)
		hashed = h[:]
	default:
		return nil, errors.New("unsupported hash algorithm")
	}

	return hashed, nil
}

// CheckMac 验证哈希校验和
func CheckMac(message, messageMac, key []byte, sha func() hash.Hash) bool {
	mac := hmac.New(sha, key)
	mac.Write(message)
	expectedMac := mac.Sum(nil)
	return hmac.Equal(messageMac, expectedMac)
}

// Sign 使用密钥签署消息并返回字节。
// 注意：对于人类可读的输出，请参阅编码/十六进制和
func Sign(message, key []byte, sha func() hash.Hash) []byte {
	mac := hmac.New(sha, key)
	mac.Write(message)
	signed := mac.Sum(nil)
	return signed
}

// Validate 验证签名 验证已采取的编码哈希值
// 通过 X-Hub-Signature HTTP Header 从 GitHub 获取。
func Validate(bytesIn []byte, encodedHash string, key string) error {
	var validated error
	var hashFn func() hash.Hash
	var payload string

	if strings.HasPrefix(encodedHash, "sha1=") {
		payload = strings.TrimPrefix(encodedHash, "sha1=")
		hashFn = sha1.New
	} else if strings.HasPrefix(encodedHash, "sha256=") {
		payload = strings.TrimPrefix(encodedHash, "sha256=")
		hashFn = sha256.New
	} else {
		return fmt.Errorf("valid hash prefixes: [sha1=, sha256=], got: %s", encodedHash)
	}
	messageMac := payload
	messageMacBuf, _ := hex.DecodeString(messageMac)
	res := CheckMac(bytesIn, messageMacBuf, []byte(key), hashFn)
	if !res {
		validated = errors.New("invalid signature")
	}
	return validated
}
